/**
 * 01 首先 VueRouter 是一个插件，Vue.js 的插件应该暴露一个 install 方法，
 *    这个方法的第一个参数是 Vue 构造器，第二个参数是一个可选的选项对象
 * 02 判断插件是否已经被安装，我们可以自定义一个变量来进行判断
 * 03 将 install 的 Vue 构造器通过全局变量缓存起来，方便使用
 * 04 VueRouter 初始化的时候会接受一个 options 参数，参数包含了路由规则
 * 05 在 install 中将路由注册到全局并且初始化
 * 06 设置初始化的方法 init 
 * 07 遍历所有的路由规则，把路由规则解析成键值对的形式，存储到 routeMap 中
 * 08 创建 router-link 和 router-view 组件
 * 09 监听 hashchange 事件、load 事件
 */

let _Vue = null

export default class VueRouter {
    // 初始化的时候会接受一个 options 参数，参数包含了路由规则
    constructor(options) {
        this.options = options

        // 将 options 中的路由规则解析出来进行存储
        this.routeMap = {}

        // data 应该是一个响应式的对象
        this.data = _Vue.observable({
            // 当前的路由地址，默认是 /
            current: "/"
        })
    }

    // install 方法
    static install (Vue) {
        // 判断插件是否已经被安装
        if (VueRouter.install.installed) return
        VueRouter.install.installed = true

        _Vue = Vue

        // 全局混入
        Vue.mixin({
            beforeCreate () {
                // 全局混入，防止组件中再次执行，因此添加逻辑判断
                // this.$options 可以获取 Vue 实例的选项
                if (this.$options.router) {
                    _Vue.prototype.$router = this.$options.router
                    this.$options.router.init()
                }
            },
        })
    }

    init () {
        this.createRouteMap()
        this.initComponents(_Vue)
        if (this.options.mode === "hash") {
            this.hashInitEvent()
        } else {
            this.historyInitEvent()
        }
    }

    createRouteMap () {
        // 遍历所有的路由规则，把路由规则解析成键值对的形式，存储到 routeMap 中
        this.options.routes.forEach(route => {
            this.routeMap[route.path] = route.component
        })
    }

    initComponents (Vue) {
        const self = this
        // 创建 router-link 组件
        Vue.component("router-link", {
            props: {
                to: String
            },
            methods: {
                hashClickHandler (e) {
                    window.location.hash = `#${this.to}`
                    this.$router.data.current = this.to
                    e.preventDefault()
                },
                historyClickHandler (e) {
                    // 调用 pushState 方法改变浏览器的地址栏
                    history.pushState({}, "", this.to)
                    this.$router.data.current = this.to
                    e.preventDefault()
                },
            },
            render (h) {
                return h("a", {
                    attrs: {
                        href: this.to
                    },
                    on: {
                        click: self.options.mode === "hash" ?
                            this.hashClickHandler :
                            this.historyClickHandler
                    }
                }, [this.$slots.default])
            }
        })

        // 创建 router-view 组件
        Vue.component("router-view", {
            render (h) {
                // 获取当前路由的路由组件
                // self.data.current 获取的是当前的路由
                // self.routeMap 存储着当前的路由规则
                const component = self.routeMap[self.data.current]
                return h(component)
            }
        })
    }

    hashInitEvent () {
        const handler = () => {
            if (!window.location.hash) {
                window.location.hash = "#/"
            }
            this.data.current = window.location.hash.substr(1)
        }

        // 监听 hashchange
        window.addEventListener("hashchange", handler)

        // 监听 load
        window.addEventListener('load', handler)
    }

    historyInitEvent () {
        window.addEventListener("popstate", () => {
            this.data.current = window.location.pathname
        })

        window.addEventListener('load', () => {
            this.data.current = window.location.pathname
        })
    }
}